PowerTCP Mail for .NET
PowerTCP and Asynchronous Programming with Async and Await



The Tasks class and the async and await keywords were introduced in .NET 4.5, providing a simpler structure for creating multi-threaded applications compared to the thread-based or single-threaded apartment models of the past. Its primary benefit is the ability to code multi-threaded/asynchronous applications with a straightforward logical structure that resembles synchronous code. Further features include passing parameters directly into the asynchronous function, directly returning return values, and catching exceptions directly around the asynchronous call. For our components, this also obsoletes the need for the Start and Marshal methods, along with the UserState and Error event (among others specific to each component).

Task.Run() may be used to execute the code specified in its lambda statement on a separate thread. Used by itself, the call immediately returns (while the lambda statement executes on its new thread), and continues on to the next line of code. When used in conjunction with await (and marking the containing method or event with the 'async' keyword), the next line of code will only be called once Task.Run returns (and, using await allows the method to return a value). While the awaited method executes on its thread, execution of the UI thread is returned to the caller of the method marked with the async keyword.

The multithreaded implementation of our 4.x components is compatible with these Tasks, and there is little difference between the use of the two; calls to PowerTCP components within Tasks are equal to calling them within a thread created with Start(). Where Start() and the UserState event were used previously:

C#
Copy Code
private void button1_Click(object sender, EventArgs e)
{
    myComponent.Start(myBlockingFunction, null);
}

private void myBlockingFunction(object myObject)
{
    //This executes on a worker thread, so it could contain 
    //any long-running code, and still not block the UI
    myComponent.Marshal("Message from the worker thread", null);
}

void myComponent_UserState(object sender, UserStateEventArgs e)
{
    MessageBox.Show(e.Message);
}
Visual Basic
Copy Code
Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles button1.Click
    myComponent.Start(AddressOf myBlockingFunction, Nothing)
End Sub

Private Sub myBlockingFunction(ByVal myObject As Object)
    'This executes on a worker thread, so it could contain 
    'any long-running code, and still not block the UI
    myComponent.Marshal("Message from the worker thread", Nothing)
End Sub

Private Sub myComponent_UserState(ByVal sender As Object, ByVal e As UserStateEventArgs)
    MessageBox.Show(e.Message)
End Sub

You can now use:

C#
Copy Code
private async void button1_Click(object sender, EventArgs e)
{
    //This call will not block the UI thread
    string taskText = await myBlockingFunctionAsync();
    MessageBox.Show(taskText);
}

private Task<string> myBlockingFunctionAsync()
{
    //This Task.Run lambda statement could contain any long-running code, and still not block the UI
    return Task.Run<string>(() =>
    {
        return "Message from Task";
    });
}
Visual Basic
Copy Code
Private Async Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles button1.Click
    'This call will not block the UI thread
    Dim taskText As String = Await myBlockingFunctionAsync()
    MessageBox.Show(taskText)
End Sub

Private Function myBlockingFunctionAsync() As Task(Of String)
    'This Task.Run lambda statement could contain any long-running code, and still not block the UI
    Return Task.Run(Of String)(Function() "Message from Task")
End Function

Which is equivalent to:

C#
Copy Code
private async void button1_Click(object sender, EventArgs e)
{
    //This call will not block the UI thread
    string taskText = await Task.Run<string>(() => { return "Message from Task"; });
    MessageBox.Show(taskText);
}
Visual Basic
Copy Code
Private Async Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles button1.Click
    'This call will not block the UI thread
    Dim taskText As String = Await Task.Run(Of String)(Function() "Message from Task")
    MessageBox.Show(taskText)
End Sub

While Task.Run() does generally obsolete the need for Start() and Marshal(), Marshal() may still be used to marshal data from the thread created with Task.Run() over to the UI thread to the UserState event or other events raised by Marshal(), as desired.


PowerTCP Mail for .NET Documentation Version 4.3
© 2018 Dart Communications. All Rights Reserved.
Send comments on this topic